package com.syl.starter.itools.common.utils.io;

import com.syl.starter.itools.base.constants.BaseConstant;
import com.syl.starter.itools.base.utils.CloseUtils;
import com.syl.starter.itools.base.utils.LogUtils;
import lombok.Cleanup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;

/**
 * 输入流工具类
 *
 * @author syl
 * @create 2018-09-15 16:17
 **/
public class InputStreamUtils {
    private static Logger LOG = LoggerFactory.getLogger(InputStreamUtils.class);

    /**
     * 最简单从流中读取字符串 自动关闭流 不指定编码
     * @param input
     * @return
     */
    public static String readStream(InputStream input){
        return readStream(input,null, true);
    }

    /**
     * 指定读取utf-8的流 自动关闭流
     * @param input
     * @return
     */
    public static String readStreamByUTF8(InputStream input){
        return readStreamByUTF8(input, true);
    }

    /**
     * 指定读取utf-8的流
     * @param input
     * @param close 是否关闭流
     * @return
     */
    public static String readStreamByUTF8(InputStream input, boolean close) {
        return readStream(input, BaseConstant.UTF8, close);
    }

    /**
     * 不指定编码获取流数据
     * @param input
     * @param close
     * @return
     */
    public static String readStream(InputStream input, boolean close) {
        return readStream(input,null,close);
    }

    /**
     * 从流中读取字符串 (不设置读取上限)
     * @param input
     * @param encoding 编码
     * @param close 是否关闭流
     * @return
     */
    public static String readStream(InputStream input, String encoding, boolean close) {
        return readStream(input,encoding,null, close);
    }

    /**
     * 从输入流中读取文件到临时文件中
     * @param input 输入流
     * @param suffix 文件后缀
     *
     * @return 临时文件路径
     * @throws Exception
     */
    public static File readToFile(InputStream input, String suffix) throws Exception {
        Path path = Files.createTempFile("temp", suffix);
        return readToFile(input, path);
    }

    /**
     * 从输入流中读取文件到指定的文件路径
     * @param input 输入流
     * @param path 要输出的目标的路径
     *
     * @return 输出后的文件路径 targetFile为空时返回null
     * @throws Exception
     */
    public static File readToFile(InputStream input, Path path) throws Exception {
        if (path == null) return null;
        return readToFile(input, path.toFile());
    }

    /**
     * 从输入流中读取文件到指定的文件路径
     * @param input 输入流
     * @param targetFile 要输出的目标的文件
     *
     * @return 输出后的文件路径 targetFile为空时返回null
     * @throws Exception
     */
    public static File readToFile(InputStream input, File targetFile) throws Exception {
        if (targetFile == null) return null;
        byte[] bytes = new byte[1024];
        @Cleanup
        OutputStream outStream = new FileOutputStream(targetFile);
        while (input.read(bytes) != -1) {
            outStream.write(bytes);
        }
        return targetFile;
    }

    /**
     * 从流中读取字符串
     * @param input 流
     * @param encoding 字符编码
     * @param maxSizeLimit 最大解析内容大小限制 k
     * @param close 是否关闭流
     * @return
     * @throws Exception
     */
    public static String readStream(InputStream input, String encoding, Integer maxSizeLimit, boolean close) {
        if (input == null) {
            LOG.info("输入流为空");
            return null;
        }
        //字节数组
        byte[] bcache = new byte[2048];
        int readSize = 0;//每次读取的字节长度
        int totalSize = 0;//总字节长度
        ByteArrayOutputStream infoStream = new ByteArrayOutputStream();
        try {
            //一次性读取2048字节
            while ((readSize = input.read(bcache)) > 0) {
                totalSize += readSize;
                if (maxSizeLimit != null && totalSize > maxSizeLimit) {
                    LOG.info("输入流超出{}大小限制",maxSizeLimit);
                    return null;
                }
                //将bCache中读取的input数据写入infoStream
                infoStream.write(bcache,0,readSize);
                return encoding == null ? infoStream.toString() : infoStream.toString(encoding);
            }
        } catch (IOException e) {
            LogUtils.error(LOG,"输入流读取异常", e);
        } finally {
            if(close)
                CloseUtils.close(input);
        }
        return null;
    }

    /**
     * 克隆流
     * 注: io流只能读取一次
     * @param input
     * @return
     */
    public static ByteArrayOutputStream cloneInputStream(InputStream input) {
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len;
            while ((len = input.read(buffer)) > -1) {
                byteArrayOutputStream.write(buffer, 0, len);
            }
            byteArrayOutputStream.flush();
            return byteArrayOutputStream;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

}
